package com.powernode.dispatch.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.powernode.common.constant.RedisConstant;
import com.powernode.dispatch.client.XxlJobClient;
import com.powernode.dispatch.mapper.OrderJobMapper;
import com.powernode.dispatch.service.NewOrderService;
import com.powernode.map.client.LocationFeignClient;
import com.powernode.model.entity.dispatch.OrderJob;
import com.powernode.model.enums.OrderStatus;
import com.powernode.model.form.map.SearchNearByDriverForm;
import com.powernode.model.vo.dispatch.NewOrderTaskVo;
import com.powernode.model.vo.map.NearByDriverVo;
import com.powernode.model.vo.order.NewOrderDataVo;
import com.powernode.order.client.OrderInfoFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Resource
    private OrderJobMapper orderJobMapper;

    @Resource
    private XxlJobClient xxlJobClient;

    @Resource
    private LocationFeignClient locationFeignClient;

    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;

    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 添加并启动定时任务
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //查询订单的任务
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getOrderId, newOrderTaskVo.getOrderId());

        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        if (orderJob == null) {
            //第一次 添加并启动定时任务
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "", "0 0/1 * * * ?", "用户下单：" + newOrderTaskVo.getOrderId());

            //向OrderJob表中添加数据
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setJobId(jobId);
            //将NewOrderTaskVo转成json数据存入
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));

            orderJobMapper.insert(orderJob);
        }

        return orderJob.getJobId();
    }


    /**
     * 1.查询任务参数
     * 2.查询订单状态
     * 3.搜索附近配送员
     * 4.给配送员派单
     */
    @Override
    public Boolean executeTask(Long jobId) {
        //1.查询任务参数
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getJobId, jobId);
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        //将json数据转成NewOrderTaskVo对象
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);

        //2.查询订单状态
        Integer orderStatus = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId()).getData();
        if (orderStatus.intValue() != OrderStatus.WAITING_ACCEPT.getStatus().intValue()) {
            //说明订单被接单或者被取消
            //停止定时任务
            xxlJobClient.stopJob(jobId);
            return true;
        }

        //3.搜索附近配送员
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());
        //nearByDriverVoList 附近的配送员数据
        List<NearByDriverVo> nearByDriverVoList = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();

        //4.给配送员派单
        nearByDriverVoList.forEach(driver -> {
            //防止重复派单  一个订单给配送员只派单1次
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST + newOrderTaskVo.getOrderId();

            Boolean isMember = redisTemplate.opsForSet().isMember(repeatKey, driver.getDriverId());
            if (!isMember) {//说明不是重复派单
                //将数据放到set中 表示已经派单
                redisTemplate.opsForSet().add(repeatKey, driver.getDriverId());

                //设置过期时间 16 分钟
                redisTemplate.expire(repeatKey, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);

                //将配送员信息放入redis的list中
                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                BeanUtils.copyProperties(newOrderTaskVo, newOrderDataVo);

                //放入redis
                String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                //list   配送员端会轮询查看自己的订单信息
                redisTemplate.opsForList().leftPush(key, JSONObject.toJSONString(newOrderDataVo));

                //设置失效时间
                redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
            }
        });

        return true;
    }


    /**
     * 配送员查询redis中派单信息
     * 配送员可能收到多个订单
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;

        Long size = redisTemplate.opsForList().size(key);
        //判断list中是否有数据
        if (size > 0) {
            for (int i = 0; i <size ; i++) {
                String content = (String)redisTemplate.opsForList().leftPop(key);
                //将上面的json字符串转成对象
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }

        return list;
    }


    /**
     * 配送员删除派单信息
     * 下班了，删除数据
     */
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        redisTemplate.delete(key);
        return true;
    }
}
